﻿package br.gov.bcb.leilao.web.componentes;

import java.math.BigDecimal;
import java.util.Locale;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormSubmitBehavior;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.util.convert.IConverter;

import br.gov.bcb.app.stuff.util.props.PropertyUtils;
import br.gov.bcb.leilao.web.converter.ValorDecimalFormatConverter;
import br.gov.bcb.wicket.stuff.util.AttributeModifierUtil;

public class ValorDecimalTextField extends TextField<BigDecimal> {

    public static final int NUMERO_CASAS_INTEIRO_DOIS = 2;
    public static final int NUMERO_CASAS_INTEIRO_TRES = 3;
    public static final int NUMERO_CASAS_INTEIRO_SEIS = 6;
    public static final int NUMERO_CASAS_INTEIRO_DOZE = 12;
    public static final int NUMERO_CASAS_INTEIRO_MAXIMO = 100;

    public static final int NUMERO_CASAS_DECIMAIS_DOIS = 2;
    public static final int NUMERO_CASAS_DECIMAIS_QUATRO = 4;
    public static final int NUMERO_CASAS_DECIMAIS_SEIS = 6;

    private static final String NEW_LINE = "\n";

    private static final String COUNTRY_BR = "BR";
    private static final String LANGUAGE_PT = "pt";
    private static final String PONTO = ".";
    private static final String VIRGULA = ",";

    private boolean permitirValorNegativo;
    private int numeroCasasInteiro = NUMERO_CASAS_INTEIRO_SEIS;
    private int numeroCasasDecimais = NUMERO_CASAS_DECIMAIS_DOIS;
    private ValorDecimalFormatConverter valorDecimalFormatConverter;

    public ValorDecimalTextField(Object property, String nomeDoCampo, boolean permitirValorNegativo,
            int numeroCasasInteiro, int numeroCasasDecimais) {
        this(PropertyUtils.property(property), nomeDoCampo, permitirValorNegativo, numeroCasasInteiro,
                numeroCasasDecimais);
    }

    public ValorDecimalTextField(String id, IModel<BigDecimal> model, String nomeDoCampo,
            boolean permitirValorNegativo, int numeroCasasInteiro, int numeroCasasDecimais) {
        this(id, nomeDoCampo, permitirValorNegativo, numeroCasasInteiro, numeroCasasDecimais);

        setModel(model);
    }

    public ValorDecimalTextField(String id, String nomeDoCampo, boolean permitirValorNegativo, int numeroCasasInteiro,
            int numeroCasasDecimais) {
        this(id, permitirValorNegativo, numeroCasasInteiro, numeroCasasDecimais);

        setLabel(new Model<String>(nomeDoCampo));
    }

    public ValorDecimalTextField(String id, boolean permitirValorNegativo, int numeroCasasInteiro,
            int numeroCasasDecimais) {
        super(id);
        this.permitirValorNegativo = permitirValorNegativo;
        this.numeroCasasInteiro = numeroCasasInteiro;
        this.numeroCasasDecimais = numeroCasasDecimais;

        setOutputMarkupId(true);

        add(new AjaxFormSubmitBehaviorOnBlur());

        AttributeModifierUtil.setAtributo(this, "title", getLabel());
        AttributeModifierUtil.setAtributo(this, "onkeypress", prepararJavaScriptVerificarCaracterDigitado());
        AttributeModifierUtil.setAtributo(this, "onkeyup", prepararJavaScriptFormatarValoresDoCampo());
        AttributeModifierUtil.setAtributo(this, "size", "18");
        AttributeModifierUtil.setAtributo(this, "maxlength", "20");
    }

    @Override
    protected void onInitialize() {
        super.onInitialize();
        valorDecimalFormatConverter =
                new ValorDecimalFormatConverter(getLocale(), permitirValorNegativo, numeroCasasInteiro,
                        numeroCasasDecimais);
    }

    private static class AjaxFormSubmitBehaviorOnBlur extends AjaxFormSubmitBehavior {

        private static final String WID_FEEDBACK = "feedback";

        public AjaxFormSubmitBehaviorOnBlur() {
            super(EventoAjax.ON_BLUR.toString());
        }

        @Override
        protected void onSubmit(AjaxRequestTarget target) {
            target.addComponent(target.getPage().get(WID_FEEDBACK));
            target.addComponent(getComponent());
        }

        @Override
        protected void onError(AjaxRequestTarget target) {
            target.addComponent(target.getPage().get(WID_FEEDBACK));
        }
    }

    @Override
    public IConverter getConverter(Class<?> type) {
        return valorDecimalFormatConverter;
    }

    private String prepararJavaScriptVerificarCaracterDigitado() {
        StringBuilder sb = new StringBuilder(NEW_LINE);

        sb.append("var zero = 48;\n");
        sb.append("var nove = 57;\n");
        sb.append("var ponto = 46;\n");
        sb.append("var virgula = 44;\n");
        sb.append("var hifen = 45;\n");
        sb.append("var key = event.keyCode;\n");
        sb.append("var teclasValidas = ((key >= zero && key <= nove) || key == ponto || key == virgula\n");
        sb.append("                    || (key == hifen && " + permitirValorNegativo + "));\n");
        sb.append("event.returnValue = teclasValidas;\n");

        return sb.toString();
    }

    private String prepararJavaScriptFormatarValoresDoCampo() {
        StringBuilder sb = new StringBuilder(NEW_LINE);

        boolean localeBR = new Locale(LANGUAGE_PT, COUNTRY_BR).equals(getLocale());
        String separadorDecimal = localeBR ? VIRGULA : PONTO;
        String separadorMilhar = localeBR ? PONTO : VIRGULA;

        String complementoRegex = separadorDecimal + (permitirValorNegativo ? "-" : "");
        String replaceSeparadorMilhar = "'$1" + separadorMilhar + "$2');\n";

        prepararJavaScriptTeclasValidasDeNavegacao(sb);
        sb.append("var elemento = event.srcElement ? event.srcElement : event.target;\n");
        sb.append("var valor = elemento.value;\n");
        sb.append("valor = valor.replace(/[^0-9" + complementoRegex + "]/g, '');\n");
        sb.append("var partes = valor.split('" + separadorDecimal + "');\n");
        sb.append("partes[0] = partes[0].replace(/(\\d{1})(\\d{21})$/, " + replaceSeparadorMilhar);
        sb.append("partes[0] = partes[0].replace(/(\\d{1})(\\d{18})$/, " + replaceSeparadorMilhar);
        sb.append("partes[0] = partes[0].replace(/(\\d{1})(\\d{15})$/, " + replaceSeparadorMilhar);
        sb.append("partes[0] = partes[0].replace(/(\\d{1})(\\d{12})$/, " + replaceSeparadorMilhar);
        sb.append("partes[0] = partes[0].replace(/(\\d{1})(\\d{9})$/, " + replaceSeparadorMilhar);
        sb.append("partes[0] = partes[0].replace(/(\\d{1})(\\d{6})$/, " + replaceSeparadorMilhar);
        sb.append("partes[0] = partes[0].replace(/(\\d{1})(\\d{3})$/, " + replaceSeparadorMilhar);
        sb.append("elemento.value = partes[0];\n");
        sb.append("if (partes.length > 1) {\n");
        sb.append("     elemento.value = partes[0] + '" + separadorDecimal + "' + partes[1];\n");
        sb.append("     if (partes[1].length >= " + numeroCasasDecimais + ") {\n");
        sb.append("         elemento.value = partes[0] + '" + separadorDecimal + "' + partes[1]\n");
        sb.append("             .substring(0, " + numeroCasasDecimais + ");\n");
        sb.append("     }\n");
        sb.append("}\n");

        return sb.toString();
    }

    private void prepararJavaScriptTeclasValidasDeNavegacao(StringBuilder sb) {
        sb.append("var backspace = 8;\n");
        sb.append("var tab = 9;\n");
        sb.append("var key = event.keyCode; \n");
        sb.append("var navegacao = ((key >= 35 && key <= 40) || key == backspace || key == tab);\n");
        sb.append("if (navegacao) {return;}\n");
    }
}